#include <iostream>
#include <fstream>
#include <vector>
#include <windows.h>
#include <conio.h>
#include <ctime>
using namespace std;

const int MAP_WIDTH = 60;
const int MAP_HEIGHT = 20;

const int HIGH_SPEED = 100;
const int MEDIUM_SPEED = 200;
const int MIN_SPEED = 300;
const int MAX_SPEED = 10;

struct Point {
    int x, y;
};

void gotoXY(int x, int y);
void setColor(int color);
void initGame();
void createfood();
void drawWelcome();
void drawInitialGame();
void updateSnakeDisplay();
void updateScoreDisplay();
void updateSpeedDisplay();
void moveSnake();
bool isKeyPressed(int key);
void checkInput();
void loadHighScore();
void saveHighScore();
void showError(const string& message, int x, int y);
void clearError(int x, int y, int length);
bool showGameOver();
void showInstructions();
char getMainMenuChoice();

vector<Point> snake;
Point food;
int direction = 2;
int score = 0;
int highest = 0;
int sleeptime = MIN_SPEED;
bool gameover = false;
clock_t lastMoveTime = 0;

void gotoXY(int x, int y) {
    COORD coord;
    coord.X = x;
    coord.Y = y;
    SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);
}

void setColor(int color) {
    SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), color);
}

void initGame() {
    snake.clear();
    snake.push_back({ MAP_WIDTH / 2, MAP_HEIGHT / 2 });
    snake.push_back({ MAP_WIDTH / 2 - 2, MAP_HEIGHT / 2 });
    snake.push_back({ MAP_WIDTH / 2 - 4, MAP_HEIGHT / 2 });
    direction = 2;
    score = 0;
    gameover = false;
    sleeptime = MIN_SPEED;
    lastMoveTime = clock();
}

void createfood() {
    bool valid;
    do {
        valid = true;
        food.x = (rand() % (MAP_WIDTH / 2 - 1)) * 2 + 2;
        food.y = rand() % (MAP_HEIGHT - 1) + 1;
        for (auto& seg : snake) {
            if (food.x == seg.x && food.y == seg.y) {
                valid = false;
                break;
            }
        }
    } while (!valid);

    gotoXY(food.x, food.y);
    setColor(12);
    cout << "★";
}

void drawWelcome() {
    system("cls");
    setColor(10);
    const char* titleArt[] = {
        "  ______               __  __                 __  ",
        " /_  __/___  _________/ /_/ /_____  _______/ /__",
        "  / / / __ \\/ ___/ __  / __/ __ \\/ ___/ __  / _ \\",
        " / / / /_/ (__  ) /_/ / /_/ /_/ / /  / /_/ /  __/",
        "/_/  \\____/____/\\__,_/\\__/\\____/_/   \\__,_/\\___/"
    };
    for (int i = 0; i < 5; ++i) {
        gotoXY(22, 5 + i);
        cout << titleArt[i];
    }

    setColor(7);
    gotoXY(35, 8);  cout << "【贪吃蛇大冒险】";
    gotoXY(35, 12); cout << "1. 开始游戏";
    gotoXY(35, 14); cout << "2. 游戏说明";
    gotoXY(35, 16); cout << "3. 退出游戏";

    setColor(6);
    gotoXY(55, 12); cout << "最高记录: " << highest;
    setColor(7);

    gotoXY(28, 20); cout << "请选择操作 (1-3): ";
    gotoXY(28, 22); cout << "                           ";
}

void drawInitialGame() {
    setColor(6);
    for (int x = 0; x <= MAP_WIDTH; x += 2) {
        gotoXY(x, 0); cout << "■";
        gotoXY(x, MAP_HEIGHT); cout << "■";
    }
    for (int y = 0; y <= MAP_HEIGHT; ++y) {
        gotoXY(0, y); cout << "■";
        gotoXY(MAP_WIDTH, y); cout << "■";
    }

    setColor(3);
    gotoXY(MAP_WIDTH + 4, 2);  cout << "当前得分: ";
    gotoXY(MAP_WIDTH + 4, 4);  cout << "最高记录: " << highest;
    gotoXY(MAP_WIDTH + 4, 6);  cout << "操作提示: ↑↓←→移动  F1加速(+2分)  F2减速(-2分)  ESC退出";
    gotoXY(MAP_WIDTH + 4, 8);  cout << "当前速度: ";
}

void updateSnakeDisplay() {
    for (size_t i = 0; i < snake.size(); ++i) {
        gotoXY(snake[i].x, snake[i].y);
        i == 0 ? setColor(14) : setColor(10);
        cout << (i == 0 ? "◎" : "●");
    }
}

void updateScoreDisplay() {
    gotoXY(MAP_WIDTH + 4 + 9, 2);
    setColor(3);
    cout << score;
}

void updateSpeedDisplay() {
    gotoXY(MAP_WIDTH + 4 + 9, 8);
    setColor(3);

    if (sleeptime > MEDIUM_SPEED) {
        cout << "低速";
    } else if (sleeptime > HIGH_SPEED) {
        cout << "中速";
    } else {
        cout << "高速";
    }
}

string getSpeedLevel() {
    if (sleeptime > MEDIUM_SPEED) {
        return "低速";
    } else if (sleeptime > HIGH_SPEED) {
        return "中速";
    } else {
        return "高速";
    }
}

void moveSnake() {
    clock_t currentTime = clock();
    if (currentTime - lastMoveTime < sleeptime) {
        return;
    }
    lastMoveTime = currentTime;

    Point head = snake[0];
    switch (direction) {
    case 1: head.y--; break;
    case 2: head.x += 2; break;
    case 3: head.y++; break;
    case 4: head.x -= 2; break;
    }

    if (head.x <= 0 || head.x >= MAP_WIDTH ||
        head.y <= 0 || head.y >= MAP_HEIGHT) {
        gameover = true;
        return;
    }

    for (auto& seg : snake) {
        if (head.x == seg.x && head.y == seg.y) {
            gameover = true;
            return;
        }
    }

    snake.insert(snake.begin(), head);

    if (head.x == food.x && head.y == food.y) {
        score += 1;
        sleeptime = max(MAX_SPEED, sleeptime - 20);
        createfood();
        updateScoreDisplay();
        updateSpeedDisplay();
    } else {
        gotoXY(snake.back().x, snake.back().y);
        cout << "  ";
        snake.pop_back();
    }

    updateSnakeDisplay();
}

bool isKeyPressed(int key) {
    static clock_t lastPress[256] = { 0 };
    if (GetAsyncKeyState(key) & 0x8000) {
        if (clock() - lastPress[key] > 100) {
            lastPress[key] = clock();
            return true;
        }
    }
    return false;
}

void checkInput() {
    if (isKeyPressed(VK_UP) && direction != 3) direction = 1;
    if (isKeyPressed(VK_RIGHT) && direction != 4) direction = 2;
    if (isKeyPressed(VK_DOWN) && direction != 1) direction = 3;
    if (isKeyPressed(VK_LEFT) && direction != 2) direction = 4;

    if (isKeyPressed(VK_F1)) {
        if (sleeptime > MAX_SPEED + 20) {
            sleeptime -= 20;
            score += 2;
            updateScoreDisplay();
            updateSpeedDisplay();
        } else if (sleeptime > MAX_SPEED) {
            sleeptime = MAX_SPEED;
            score += 2;
            updateScoreDisplay();
            updateSpeedDisplay();
        }
    }

    if (isKeyPressed(VK_F2)) {
        if (sleeptime < MIN_SPEED - 20) {
            sleeptime += 20;
            score = max(0, score - 2);
            updateScoreDisplay();
            updateSpeedDisplay();
        } else if (sleeptime < MIN_SPEED) {
            sleeptime = MIN_SPEED;
            score = max(0, score - 2);
            updateScoreDisplay();
            updateSpeedDisplay();
        }
    }

    if (isKeyPressed(VK_ESCAPE)) gameover = true;
}

void loadHighScore() {
    ifstream file("save.txt");
    if (file) file >> highest;
}

void saveHighScore() {
    if (score > highest) {
        ofstream file("save.txt");
        if (file) file << score;
        highest = score;
    }
}

void showError(const string& message, int x, int y) {
    gotoXY(x, y);
    setColor(12);
    cout << message;
}

void clearError(int x, int y, int length) {
    gotoXY(x, y);
    cout << string(length, ' ');
}

bool showGameOver() {
    system("cls");
    setColor(14);
    gotoXY(25, 5); cout << "=== 游戏结束 ===";
    gotoXY(25, 7); cout << "最终得分: " << score;

    saveHighScore();

    if (score >= highest) {
        gotoXY(25, 9); cout << "★ 新纪录诞生! ★";
    } else {
        gotoXY(25, 9); cout << "距离最高分: " << highest - score;
    }

    setColor(7);
    gotoXY(25, 12); cout << "感谢游玩本游戏！";
    gotoXY(25, 14); cout << "1. 重玩  2. 退出";
    clearError(25, 16, 30);

    while (_kbhit()) _getch();

    while (true) {
        if (_kbhit()) {
            char endChoice = _getch();

            if (endChoice == '1') {
                return true;
            } else if (endChoice == '2') {
                return false;
            } else {
                showError("输入错误，请重新选择 (1 或 2)", 25, 16);
            }
        }
    }
}

void showInstructions() {
    system("cls");
    setColor(11);
    gotoXY(28, 3); cout << "=== 游戏说明 ===";
    setColor(7);
    gotoXY(20, 5);  cout << "方向键控制移动";
    gotoXY(20, 6);  cout << "F1加速(+2分)/F2减速(-2分)";
    gotoXY(20, 7);  cout << "吃到食物自动加速并加1分";
    gotoXY(20, 8);  cout << "速度档位: 低速(300-200ms) 中速(200-100ms) 高速(100-10ms)";
    gotoXY(20, 11); cout << "按任意键返回...";

    while (_kbhit()) _getch();
    _getch();
}

char getMainMenuChoice() {
    while (_kbhit()) _getch();

    while (true) {
        if (_kbhit()) {
            char choice = _getch();
            if (choice >= '1' && choice <= '3') {
                clearError(28, 22, 30);
                return choice;
            } else {
                showError("输入错误，请重新选择 (1-3)", 28, 22);
            }
        }
    }
}

int main() {
    SetConsoleOutputCP(65001);
    srand(time(NULL));
    loadHighScore();
    CONSOLE_CURSOR_INFO cursor = { 1, FALSE };
    SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cursor);

    while (true) {
        drawWelcome();
        char choice = getMainMenuChoice();

        if (choice == '1') {
            bool replay = true;
            while (replay) {
                initGame();
                system("cls");
                drawInitialGame();
                createfood();
                updateSnakeDisplay();
                updateScoreDisplay();
                updateSpeedDisplay();

                while (!gameover) {
                    checkInput();
                    moveSnake();
                    Sleep(10);
                }

                replay = showGameOver();
            }
        }
        else if (choice == '2') {
            showInstructions();
        }
        else if (choice == '3') {
            system("cls");
            setColor(7);
            gotoXY(25, 10); cout << "欢迎再次游玩！";
            Sleep(1500);
            break;
        }
    }

    setColor(7);
    return 0;
}